"""
utils.py
By IT小强xqitw.cn <mail@xqitw.cn>
At 6/19/21 8:23 AM
"""
import os
import re
import sys
import ctypes
import subprocess
from pathlib import Path


def popen(command, **kwargs):
    try:
        startupinfo = subprocess.STARTUPINFO()
        startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
    except (ImportError, AttributeError):
        startupinfo = None
    process = subprocess.Popen(
        command,
        startupinfo=startupinfo,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        stdin=subprocess.PIPE,
        shell=True,
        **kwargs
    )
    return process


def run_cmd(command, encoding='gbk'):
    """
    执行自定义命令
    :param encoding:
    :param command:
    :return:
    """
    process = popen(command=command, encoding=encoding)
    try:
        process.encoding = 'gbk'
        result = process.stdout.read()
    except UnicodeDecodeError:
        process.encoding = 'utf8'
        result = process.stdout.read()
    return result


def run_cmd_line(command, encoding='gbk'):
    """
    执行自定义命令
    :param encoding:
    :param command:
    :return:
    """
    process = popen(command=command, encoding=encoding)
    while True:
        line = process.stdout.readline()
        if not line:
            break
        yield line


def resource_path(*relative_path):
    """
    获取 资源绝对路径
    :param relative_path:
    :return:
    """
    # PyInstaller会创建临时文件夹temp
    # 并把路径存储在_MEIPASS中
    if hasattr(sys, '_MEIPASS'):
        base_path = sys._MEIPASS
    else:
        base_path = str(Path(__file__).resolve(strict=True).parent.parent)
    return os.path.join(base_path, *relative_path)


def get_user_home_path():
    """
    获取用户主目录
    :return:
    """
    user_home_path = ''
    try:
        user_home_path = os.environ['HOME']
    except KeyError:
        user_home_path = os.path.expanduser('~')
        if not user_home_path:
            user_home_path = os.path.expandvars('$HOME')
    finally:
        return user_home_path


def create_settings_path(path_name='.wsl2_auto_port_forward'):
    """
    创建并返回配置目录
    :param path_name:
    :return:
    """
    user_home_path = get_user_home_path()
    settings_path = os.path.join(user_home_path, path_name)
    if not os.path.isdir(settings_path):
        os.mkdir(settings_path)
    return settings_path


def get_int_value(value, default=0):
    """
    强制转换为整型
    :param default:
    :param value:
    :return:
    """
    try:
        return int(value)
    except ValueError:
        return default


def get_int_range(value):
    """
    端口范围解析
    :param value:
    :return:
    """
    value = str(value).strip()
    _port_list = []
    _re_match = re.match(r'^(\d+)-(\d+)$', value)
    if _re_match:
        num1, num2 = int(_re_match.group(1)), int(_re_match.group(2))
        if num1 > num2:
            num1, num2 = num2, num1
        for num in range(num1, num2 + 1):
            _port_list.append(num)
    else:
        _port_list.append(value)
    return _port_list


def get_ports_from_string(port_string):
    """
    解析字符串，提取全部端口号
    :param port_string:
    :return:
    """
    port_list = []
    if isinstance(port_string, (str, int)):
        port_lines = str(port_string).strip().splitlines()
        for port_line in port_lines:
            if not port_line:
                continue
            _port_line = port_line.strip()
            _port_line = port_line.replace(',', ' ').replace('，', ' ').replace(';', ' ').replace('；', ' ')
            _port_list = _port_line.split()
            for _port_item in _port_list:
                port_list += get_int_range(_port_item)
    else:
        port_list = list(port_string)
    return sorted([
        get_int_value(port)
        for port in list(set(port_list))
        if get_int_value(port) > 0
    ])


def signal_emit_text(signal, obj, text):
    """
    推送字符串数据
    :param signal:
    :param obj:
    :param text:
    :return:
    """
    signal.emit(obj, str(text))


def is_user_an_admin():
    """
    是否为超级管理员
    :return:
    """
    _is_user_an_admin = False
    try:
        _uid = os.geteuid()
        if _uid == 0:
            return True
    except (ImportError, AttributeError):
        pass

    try:
        _is_user_an_admin = bool(ctypes.windll.shell32.IsUserAnAdmin())
    except (ImportError, AttributeError):
        pass

    return _is_user_an_admin
